<template>
  <div class="container">
    <el-form ref="form" :model="form" :rules="rules" label-width="150px">
      <!-- 名称 -->
      <el-form-item label="名称" prop="name">
        <el-input v-model="form.name" placeholder="请填写名称" clearable/>
      </el-form-item>

      <!-- 菜单资源权限 -->
      <el-form-item
          label="菜单资源权限"
          prop="menuIds"
          v-if="form.menuList && form.menuList.length > 0"
      >
        <div class="menuListWrapper">
          <div v-for="(item, index) in form.menuList" :key="item.id" class="menuList">
            <div class="systemName">{{ item.name }}</div>
            <el-tree
                class="menuTree"
                :data="item.menus"
                show-checkbox
                node-key="id"
                :props="defaultProps"
                @check="(node, checked) => handleCheckChange(node, checked, item)"
                :ref="setTreeRef(index)"
            />
          </div>
        </div>
      </el-form-item>

      <!-- 备注 -->
      <el-form-item label="备注" prop="remark">
        <el-input
            size="small"
            v-model="form.remark"
            placeholder="请填写备注"
            type="textarea"
            :autosize="{ minRows: 2, maxRows: 4 }"
            show-word-limit
            maxlength="99"
        />
      </el-form-item>

      <!-- 设为默认 -->
      <el-form-item label="设为默认" prop="defaultFlag">
        <el-switch v-model="form.defaultFlag" active-color="#13ce66"/>
      </el-form-item>

      <!-- 操作按钮 -->
      <el-form-item>
        <el-button type="primary" size="small" @click="saveEdit">保存</el-button>
        <el-button size="small" @click="goBack">取消</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
import {
  roleDetailExtendApi,
  roleSaveApi,
  roleEditApi,
} from "../../../api/mgt/power/role";
import {menuListByRoleIdApi} from "../../../api/mgt/power/menu";
import {deepCopy, createObjectBase, getTreeByCheck} from "@/utils";

const obj = {
  id: "",
  name: "",
  code: "",
  defaultFlag: false,
  remark: "",
  menuIds: [],
  resourceIds: [],
};

export default {
  data() {
    return {
      form: deepCopy(obj),
      defaultProps: {
        children: "children",
        label: "name",
      },
      selectedMenuIdsBySystem: [],
      treeRefs: [],
      rules: {
        name: [
          {required: true, message: "请填写名称", trigger: "change"},
          {max: 20, message: "长度不能超过20个字符", trigger: "change"},
        ],
        remark: [
          {max: 99, message: "长度不能超过99个字符", trigger: "change"},
        ],
      },
    };
  },
  methods: {
    setTreeRef(index) {
      return (el) => {
        this.treeRefs[index] = el;
      };
    },

    getDetail(id) {
      if (!id) {
        if (this.$refs.form) {
          this.$refs.form.resetFields();
        }
        menuListByRoleIdApi().then((res) => {
          this.form.menuList = res?.bizData || [];
          this.initSelectedMenuIdsBySystem();
        });
      } else {
        Promise.all([
          roleDetailExtendApi({id}),
          menuListByRoleIdApi({roleId: id}),
        ]).then(([roleDetail, menuList]) => {
          const formData = Object.assign(deepCopy(roleDetail?.bizData), {
            menuList: menuList?.bizData || []
          });
          this.form = formData;
          this.initSelectedMenuIdsBySystem();
        });
      }
    },

    initSelectedMenuIdsBySystem() {
      this.selectedMenuIdsBySystem = {};
      (this.form.menuList || []).forEach((system) => {
        const menuIds = [], resourceIds = [];
        const walk = (arr) =>
            arr.forEach((n) => {
              if (n.type === '0') {
                if (n.checked) menuIds.push(n.id);
              } else {
                if (n.checked) resourceIds.push(n.id);
              }
              if (n.children) walk(n.children);
            });
        walk(system.menus);
        this.selectedMenuIdsBySystem[system.id] = {
          menuIds: [...new Set(menuIds)],
          resourceIds: [...new Set(resourceIds)],
        };
      });
      this.$nextTick(this.setDefaultCheckedKeys);
    },

    // 1. 回显
    setCheckedWithIndeterminate(tree, nodes, checkedSet) {
      if (!tree) return;
      const leaf = [];
      const walk = arr => arr.forEach(n => {
        if (n.children?.length) {
          walk(n.children);
          return
        }
        if (checkedSet.has(n.id)) leaf.push(n.id);
      });
      walk(nodes);
      tree.setCheckedKeys(leaf, false);

      // 2. 补半选
      const walk2 = arr => arr.forEach(n => {
        if (!n.children?.length) return;
        const childIds = n.children.map(c => c.id);
        const checkedCount = childIds.filter(id => checkedSet.has(id)).length;
        if (checkedCount && checkedCount < childIds.length) {
          const node = tree.getNode(n.id);
          if (node) node.indeterminate = true;
        }
        walk2(n.children);
      });
      walk2(nodes);
    },

    flattenToMap(arr, map = new Map(), idKey = 'id', typeKey = 'type', childrenKey = 'children') {
      arr.forEach(n => {
        map.set(n[idKey], n[typeKey]);
        if (n[childrenKey]) this.flattenToMap(n[childrenKey], map, idKey, typeKey, childrenKey);
      });
      return map;
    },

    setDefaultCheckedKeys() {
      this.form.menuList.forEach((sys, i) => {
        const {menuIds = [], resourceIds = []} = this.selectedMenuIdsBySystem[sys.id] || {};
        this.setCheckedWithIndeterminate(this.treeRefs[i], sys.menus, new Set([...menuIds, ...resourceIds]));
      });
    },

    handleCheckChange(node, checked, system) {
      // 1. 当前这棵树的「全选 + 半选」id 集合
      const allIds = [...new Set([...checked.checkedKeys, ...checked.halfCheckedKeys])];

      // 2. 把当前系统所有节点拍平成 Map<id, type>
      const nodeMap = this.flattenToMap(system.menus);

      // 3. 按类型归类
      const menuIds = [], resourceIds = [];
      allIds.forEach(id => {
        (nodeMap.get(id) === '0' ? menuIds : resourceIds).push(id);
      });

      // 4. 落地
      this.selectedMenuIdsBySystem[system.id] = {
        menuIds: [...new Set(menuIds)],
        resourceIds: [...new Set(resourceIds)]
      };
    },

    saveEdit() {
      this.$refs.form.validate((valid) => {
        if (valid) {
          const data = createObjectBase(this.form, Object.keys(obj));
          const {id} = data;
          const menuIds = [], resourceIds = [];
          Object.values(this.selectedMenuIdsBySystem).forEach((v) => {
            menuIds.push(...v.menuIds);
            resourceIds.push(...v.resourceIds);
          });
          data.menuIds = [...new Set(menuIds)];
          data.resourceIds = [...new Set(resourceIds)];
          const fn = id ? roleEditApi : roleSaveApi;
          fn(data).then(() => {
            this.goBack();
          });
        } else {
          return false;
        }
      });
    },

    goBack() {
      this.$router.goPage({path: "/role/page"});
    },
  },
  created() {
    const {id} = this.$route.query;
    this.getDetail(id);
  },
};
</script>

<style scoped>
.menuListWrapper {
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  padding: 8px;
}

.menuTree {
  flex: 1 1 auto;
  min-width: 0;
  overflow: visible;
}

.menuListWrapper ::v-deep .el-tree-node__children {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding-left: 0 !important;
}

.menuListWrapper ::v-deep .el-tree-node.is-leaf {
  flex: none;
  white-space: nowrap;
}

.menuListWrapper ::v-deep .el-tree-node.is-leaf .el-tree-node__label {
  padding: 4px 8px;
  background: #f0f2f5;
  border-radius: 4px;
  font-size: 13px;
  line-height: 1.4;
}

.menuListWrapper ::v-deep .el-tree-node.is-leaf .el-tree-node__content {
  height: 32px;
  line-height: 32px;
  padding: 0 8px;
  border-radius: 4px;
  background: #f0f2f5;
}

.menuListWrapper ::v-deep .el-tree-node__content {
  display: block;
  height: auto;
  line-height: 32px;
}

.menuListWrapper ::v-deep .el-tree-node__children {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 8px;
  padding-left: 0;
  margin-left: var(--indent);
}

.menuListWrapper ::v-deep .el-tree > .el-tree-node > .el-tree-node__children {
  padding-left: 20px !important;
}

.menuListWrapper ::v-deep .el-tree > .el-tree-node > .el-tree-node__children > .el-tree-node > .el-tree-node__children {
  padding-left: 20px !important;
}

.menuListWrapper ::v-deep .el-tree > .el-tree-node > .el-tree-node__children > .el-tree-node > .el-tree-node__children > .el-tree-node > .el-tree-node__children {
  padding-left: 20px !important;
}

.menuList {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 8px;
}

.systemName {
  flex: 0 0 120px;
  display: flex;
  align-items: center;
  height: 32px;
}

@media (max-width: 768px) {
  .menuList {
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
  }

  .systemName {
    font-size: 14px;
  }

  .menuTree {
    max-width: 100%;
  }
}
</style>
